#include "types.h"
#include "defs.h"
#include "param.h"
#include "mmu.h"
#include "swapper.h"
#include "fs.h"
#include "file.h"
#include "proc.h"
#include "stat.h"
#include "fcntl.h"

void getFileName(int pid, char* result) {
	int i;
	char* sp;
	char tmp[6];
	char* tp = tmp;
	int val = pid;

	while (val || tp == tmp) {
		i = val % 10;
		val = val / 10;
		*tp++ = i + '0';
	}

	sp = result;
	while (tp > tmp)
		*sp++ = *--tp;
	*sp++ = '.';
	*sp++ = 's';
	*sp++ = 'w';
	*sp++ = 'a';
	*sp++ = 'p';
	*sp = 0;
}

struct inode* createSF(char *path, short type, short major, short minor) {
	uint off;
	struct inode *ip, *dp;
	char name[DIRSIZ];

	if ((dp = nameiparent(path, name)) == 0)
		return 0;
	ilock(dp);

	if ((ip = dirlookup(dp, name, &off)) != 0) {
		iunlockput(dp);
		ilock(ip);
		if (type == T_FILE && ip->type == T_FILE)
			return ip;
		iunlockput(ip);
		return 0;
	}

	if ((ip = ialloc(dp->dev, type)) == 0)
		panic("create: ialloc");

	ilock(ip);
	ip->major = major;
	ip->minor = minor;
	ip->nlink = 1;
	iupdate(ip);

	if (type == T_DIR) { // Create . and .. entries.
		dp->nlink++; // for ".."
		iupdate(dp);
		// No ip->nlink++ for ".": avoid cyclic ref count.
		if (dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
			panic("create dots");
	}

	if (dirlink(dp, name, ip->inum) < 0)
		panic("create: dirlink");

	iunlockput(dp);
	return ip;
}

int fdallocSF(struct file *f, struct proc *p) {
	int fd;

	for (fd = 0; fd < NOFILE; fd++) {
		if (p->ofile[fd] == 0) {
			p->ofile[fd] = f;
			return fd;
		}
	}
	return -1;
}

int createSwapFile(int pid, struct proc* p, int omode) {
	int fd;
	struct file *f;
	struct inode *ip;
	char path[20] = {0};

	getFileName(pid, path);
	if (omode & O_CREATE) {
		if ((ip = createSF(path, T_FILE, 0, 0)) == 0)
			return -1;
	} else {
		if ((ip = namei(path)) == 0)
			return -1;
		ilock(ip);
		if (ip->type == T_DIR && omode != O_RDONLY) {
			iunlockput(ip);
			return -1;
		}
	}

	if ((f = filealloc()) == 0 || (fd = fdallocSF(f, p)) < 0) {
		if (f)
			fileclose(f);
		iunlockput(ip);
		return -1;
	}
	iunlock(ip);

	f->type = FD_INODE;
	f->ip = ip;
	f->off = 0;
	f->readable = !(omode & O_WRONLY);
	f->writable = (omode & O_WRONLY) || (omode & O_RDWR);

	return fd;
}

void closeSwapFile(int filedesc, struct proc *p) {
	fileclose(p->ofile[filedesc]);
}
